﻿using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Core.Utility.Helper
{   
    
    /// <summary>
    /// Json转类
    /// </summary>
    public class JsonToClassHelper
    {
        /// <summary>
        /// Json转类
        /// </summary>
        /// <param name="json"></param>
        /// <param name="className">类名</param>
        /// <returns></returns>
        public static string JsonToClass(string json,string className)
        {

            var jt = JsonConvert.DeserializeObject<JObject>(json);
            StringBuilder sb = new StringBuilder();
            //RequestRoot
            sb.AppendLine($"public class {className}");
            sb.AppendLine("{");
            if (jt != null)
            {
                foreach (JToken item in jt.Children())
                {
                    JTokenToClass(item, sb);
                }
            }
            sb.AppendLine("}");
            var s = sb.ToString();
            return s;
        }


        /// <summary>
        /// JToken转类
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="sb"></param>
        public static void JTokenToClass(JToken obj, StringBuilder sb)
        {
            if (obj.Type == JTokenType.Property)
            {
                JPropertyToClass(obj as JProperty, sb);
            }
            else if (obj.Type == JTokenType.Object)
            {
                JObjectToClass(obj as JObject, sb);
            }
            else if (obj.Type == JTokenType.Array)
            {
                JArrayToClass(obj as JArray, sb);
            }
            else
            {

            }
        }
        /// <summary>
        /// JProperty转类
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="sb"></param>
        public static void JPropertyToClass(JProperty? obj, StringBuilder sb)
        {
            if (obj != null)
            {
                var pn = obj.Name;
                foreach (var item in obj.Children())
                {
                    if (!IsObject(obj, item, sb))
                    {
                        JTokenToClass(item, sb);
                    }
                }
            }
        }

        /// <summary>
        /// 是否为对象
        /// </summary>
        /// <param name="jp"></param>
        /// <param name="jo"></param>
        /// <param name="sb"></param>
        /// <returns></returns>
        public static bool IsObject(JProperty? jp, JToken? jo, StringBuilder sb)
        {
            if (jp != null && jo != null)
            {
                if (jo.Type == JTokenType.String
                    || jo.Type == JTokenType.Integer
                    || jo.Type == JTokenType.Float
                    || jo.Type == JTokenType.Boolean
                    || jo.Type == JTokenType.Null
                    )
                {
                    var type = jo.Type.ToString()
                        .Replace("String", "string")
                        .Replace("Integer", "int")
                        .Replace("Float", "float")
                        .Replace("Boolean", "bool")
                          // null 当作string
                          .Replace("Null", "string")
                        ;
                    sb.AppendLine();
                    sb.AppendLine($" /// <summary> {jo} </summary>");
                    sb.AppendLine($"public {type} {jp?.Name} {{get; set; }} =\"{jo}\";");

                    return true;
                }
                else if (jo.Type == JTokenType.Property
                    || jo.Type == JTokenType.Array)
                { }
                else
                {


                    Console.WriteLine(jo.Type.ToString());
                }
            }
            return false;

            // None = 0,
            //Object = 1,
            //Array = 2,
            //Constructor = 3,
            //Property = 4,
            //Comment = 5,
            //Integer = 6,
            //Float = 7,
            //String = 8,
            //Boolean = 9,
            //Null = 10,
            //Undefined = 11,
            //Date = 12,
            //Raw = 13,

            //Bytes = 14,
            //Guid = 15,
            //Uri = 16,
            //TimeSpan = 17
        }

        /// <summary>
        /// JArray转Class
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="sb"></param>
        public static void JArrayToClass(JArray? obj, StringBuilder sb)
        {
            // 无名称去掉索引
            if (obj != null)
            {
                var pn = obj.Path;
                if (pn.Contains("[0]."))
                {
                    //?.Replace("[0].", "")
                    var li = pn.IndexOf("[0].") + 4;
                    pn = pn.Substring(li, pn.Length - li);
                }


                //集合只解析第一个
                if (obj.HasValues)
                {
                    var cn = pn + "_class";
                    sb.AppendLine();
                    sb.AppendLine($"public  List<{cn}> {pn};");
                    sb.AppendLine();
                    sb.AppendLine($"public class {cn}");
                    sb.AppendLine("{");

                    var fb = obj.Children().FirstOrDefault();
                    JTokenToClass(fb, sb);
                    sb.AppendLine("}");
                }
                else
                {
                    sb.AppendLine($"public object {pn};");
                }
            }
        }

        /// <summary>
        /// JObject转类
        /// </summary>
        /// <param name="jo"></param>
        /// <param name="sb"></param>
        public static void JObjectToClass(JObject? jo, StringBuilder sb)
        {
            if (jo != null)
            {
                // object 时需要生成类型声明
                foreach (JToken item in jo.Children())
                {
                    JTokenToClass(item, sb);
                }
            }
        }
    }
}
